package org.deri.feather.loader;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;

import org.deri.feather.common.IRIElement;
import org.deri.feather.common.LiteralElement;
import org.deri.feather.common.StringTools;
import org.deri.feather.common.Triple;
import org.deri.feather.indexer.Indexer;

public class TurtleLoader {

	Indexer indexer;
	private String namedGraphIRI;
	private Map<String,String> namespaces;
	
	/**
	 * 
	 * @param namedGraphURI
	 */
	public void setUp(String namedGraphIRI){
		indexer = new Indexer();
		indexer.setUp();
		this.namedGraphIRI = namedGraphIRI;
		this.namespaces = new HashMap<String,String>();
		}
	
	/**
	 * Load Triples from filename into Lucene.
	 * 
	 * @param filename
	 */
	public void load(String filename){
		/*
		 * Read line by line..
		 * 1 - If the line starts with # then forget it
		 * 2 - If the line starts with @ then process namespace
		 * 3 - Otherwise, parse the triple.
		 */
		System.out.println("Reading triples from " + filename);		  	
		String line = "";
		
		try {
			BufferedReader in = new BufferedReader(new FileReader(filename));
			long count = 0;
	  	    while ((line = in.readLine()) != null) {
	
	  	    	if (line.startsWith("@"))
	  	    		processNamespace(line);
	  	    	
	  	    	if (line.startsWith("<")){
	  	    		Triple triple = processTriple(line);
	  	    		indexer.index(triple, namedGraphIRI);
	  	    		if((++count % 10000) == 0){
		    			System.out.println(count + " triples indexed");
		    			indexer.commit();
		    		}
	  	    	}
	  	    }
	  	    indexer.close();
	  	    in.close();
	  	} catch (Exception e) {
	  		e.printStackTrace();
	  		System.out.println("Error reading data.");
	  	} 
	  	
		System.out.println("[DONE]");
	}
	
	private void processNamespace(String text) {
		String alias = "";
		String namespace = "";
		
		if (text.startsWith("@base")) {
			alias = "base";
		} else {
			text = text.replace("@prefix","").trim();
			alias = text.substring(0,text.indexOf(":"));
		}
		namespace = text.substring(text.indexOf("<")+1, text.indexOf(">"));

		this.namespaces.put(alias, namespace);
	}
	
	private Triple processTriple(String text) {
		text = text.substring(0, text.lastIndexOf('.')).trim();

	    Triple triple;
	    String subject = "";
	    String predicate = "";
	    String object = "";
	    
	    subject = processSubject(text.substring(1,text.indexOf(">")));
	    		
	    text = text.substring(text.indexOf(">")+1).trim();
	    if (text.startsWith("<"))
	    	predicate = text.substring(1,text.indexOf(">"));
	    else
	    	predicate = text.substring(0,text.indexOf("\t"));
	    predicate = processPredicate(predicate);
	    
	    text = text.substring(text.indexOf("\t")).trim();
	    if (text.startsWith("<"))
	    	object = text.substring(1, text.indexOf(">"));
	    else
	    	object = text;
	    object = processObject(object);
	    
    	if (StringTools.isURI(object))
    		triple = new Triple(new IRIElement(subject), new IRIElement(predicate), 
    			new IRIElement(object), new IRIElement(this.namedGraphIRI));
    	else
    		triple = new Triple(new IRIElement(subject), new IRIElement(predicate), 
    		new LiteralElement(object), new IRIElement(this.namedGraphIRI));

		return triple;

	}
	
	private String processSubject(String text) {
		String subject = text;
		
		if (StringTools.isURI(subject))
			return subject;
	
		String namespace = detectNamespace(subject);
		if (namespace.isEmpty()) {
	    	subject =  this.namespaces.get("base") + subject;
		} else {
	    	subject = namespace + subject.substring(subject.indexOf(":") +1);
		}
	    	
		return subject;
	}
	
	private String processPredicate(String text) {
		String predicate = text;
		
		if (StringTools.isURI(predicate))
			return predicate;
		
		String namespace = detectNamespace(predicate);
		if (namespace.isEmpty()) {
	    	predicate = this.namespaces.get("base") + predicate;
		} else {
	    	predicate = namespace + predicate.substring(predicate.indexOf(":") +1);
		}
		
		return predicate;
	}
	
	private String processObject(String text) {
		String object = text;
		
		if(object.contains("^^")) {
			String type = object.substring(object.indexOf("^^")+2).replace("<", "").replace(">", "");
			if (!StringTools.isURI(type))
				type = detectNamespace(type) + type.substring(type.indexOf(":")+1);
			object = object.substring(0,object.indexOf("^^")+2) + type;
		}
		
		return object;
	}
	
	private String detectNamespace(String text) {
		if (!text.contains(":"))
			return "";
		
		String alias = text.substring(0,text.indexOf(":"));
		if (!this.namespaces.containsKey(alias))
			return "";
		
		return this.namespaces.get(alias);
	}

}
